-- description: 幻读 Phantom Read
-- date: 2024-03-20 21:56
-- author: liyf
-- database: study
-- table: account
-- comment: 幻读：当事务隔离级别为 repeatable read 或默认时，在同一个事务内，两次执行相同的查询得到的结果集不一致。这是因为在两次执行查询之间，另一个事务插入、更新或删除了符合查询条件的数据。


-- 测试数据
drop table if exists account;
create table account(
                        id int primary key AUTO_INCREMENT comment 'ID',
                        name varchar(10) comment '姓名',
                        money double(10,2) comment '余额'
) comment '账户表';
insert into account(name, money) VALUES ('张三',2000), ('李四',2000);

-- 幻读演示
-- 打开两个命令行窗口执行
-- 1. 修改会话1隔离级别为 READ COMMITTED
set session TRANSACTION ISOLATION LEVEL Repeatable Read ;

-- 2. 在会话1中开启事务并执行查询
begin;
select * from account where id = 3;
# Empty set (0.02 sec)

-- 3. 在会话2中开始事务
begin;

-- 4. 在会话2中执行插入语句并提交事务
insert into account values(3, '王五',1000);
# Query OK, 1 row affected (0.01 sec)
commit;

-- 5. 再次回到会话1中执行插入操作
insert into account values(3, '马六', 9999);
# ERROR 1062 (23000): Duplicate entry '3' for key 'account.PRIMARY'

-- 6. 再次回到会话1中执行查询操作
select * from account where id = 3;
# Empty set (0.00 sec)

-- 7. 再次回到会话1中执行提交操作
commit;


-- 8. 再次回到会话1中执行查询操作
select * from account where id = 3;
# +----+------+---------+
# | id | name | money   |
# +----+------+---------+
# |  3 | 王五 | 1000.00 |
# +----+------+---------+
# 1 row in set (0.01 sec)

-- 解决幻读演示

-- 打开两个命令行窗口执行
-- 1. 修改会话1默认隔离级别
set session TRANSACTION ISOLATION LEVEL serializable;

-- 2. 在会话1中开启事务并执行查询
begin;
select * from account where id = 4;
# Empty set (0.00 sec)

-- 3. 在会话1中插入数据
insert into account values(4, '马六甲', 999);
# Query OK, 1 row affected (0.00 sec)

-- 4. 在会话2中开始事务
begin;

-- 5. 在会话2中执行插入语句
insert into account values(4, '马六',100);

-- 6. 再次回到会话1中提交
commit;

-- 7. 回到会话2中 发现错误
# ERROR 1062 (23000): Duplicate entry '4' for key 'account.PRIMARY'

-- 8. 在会话2中提交事务
commit;